/*
 Copyright 2010 Victor Mayoral Vilches

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

//
//  LandscapeViewController.m
//  NaoRemote
//
//  Created by Victor Mayoral Vilches on 24/01/10.
//  Copyright 2010 __MyCompanyName__. All rights reserved.
//
/*
 Esta clase es la encargada de mostrar en "landscape" la interfaz para teleoperar a Nao
 
 */

#import "LandscapeViewController.h"
#import "PruebaView.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <CoreGraphics/CoreGraphics.h>
#import "PresentacionViewController.h"

#define PORT "54010" // default the port client will be connecting to 
#define MAXDATASIZE 100 // max number of bytes we can get at once 
#define MAXIMAGESIZE 500000 // max number of bytes we can get at once 


#define VIDEO_ON "1"
#define VIDEO_OFF "0"



@implementation LandscapeViewController

@synthesize subview;


// the designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
	{
        self.wantsFullScreenLayout = YES; // we want to overlap the status bar.
        
		// when presented, we want to display using a cross dissolve
		self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
    }
    return self;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    
    oldStatusBarStyle = [[UIApplication sharedApplication] statusBarStyle];    
//    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:NO];
    [[UIApplication sharedApplication] setStatusBarHidden:YES];
    
    //Hacemos que poco a poco desaparezca la etiqueta de landscapeb    
//    etiq.text = direccion_ip_host;
    
    //Creamos una cola de operaciones:
    aQueue = [[NSOperationQueue alloc] init];

    
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    
//    [[UIApplication sharedApplication] setStatusBarStyle:oldStatusBarStyle animated:NO];
        [[UIApplication sharedApplication] setStatusBarHidden:NO];
}

// override to allow orientations other than the default portrait orientation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{

    //Cada vez que queramos rotar desactivamos el video:
    videoEstate = (int) VIDEO_OFF;
    // return YES for supported orientations
    return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad 
{
    videoEstate = (int)VIDEO_OFF;    
}    

- (void)dealloc {
    [super dealloc];
}

#pragma mark -
#pragma Conexion red

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }
    
    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}



void sendMessage(char * linea, char * ip_cadena, char * port_cadena){
    
    //Declaración de variables	
    int sockfd, numbytes;  
    char buf[MAXDATASIZE];
    struct addrinfo hints, *servinfo, *p;
    int rv;
    char s[INET6_ADDRSTRLEN];
    int bytes_sent;
    char mensaje[50];
    
    
    printf("Trying to conect to: %s at port %s \n",ip_cadena, port_cadena);
    
    //Formamos el struct hints
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    
    if ((rv = getaddrinfo(ip_cadena, port_cadena, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return;
    }
    
    // loop through all the results and connect to the first we can
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                             p->ai_protocol)) == -1) {
            perror("client: socket");
            continue;
        }
        
        if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
            close(sockfd);
            perror("client: connect");
            continue;
        }
        
        break;
    }
    
    if (p == NULL) {
        fprintf(stderr, "client: failed to connect\n");
        return;
    }
    
    inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
              s, sizeof s);
    
    //----------------------------------------------------------------
    //				SEND		WALK    MESSAGE
    //----------------------------------------------------------------
    
    printf("client: connecting to %s\n", s);    
    
    if (bytes_sent = send(sockfd, linea, sizeof(mensaje), 0) == -1) 
        perror("send"); 				
    
    //	Writeline(sockfd, mensaje, sizeof(mensaje));	
    
    //----------------------------------------------------------------
    //----------------------------------------------------------------
    
    
    //freeaddrinfo(servinfo); // all done with this structure
    
    if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
        perror("recv");
        exit(1);
    }
    
    buf[numbytes] = '\0';
    
    printf("client: received '%s'\n",buf);
    close(sockfd);            
}

char* askForImage(char * ip_cadena, char * port_cadena)
{
    
    //---------------------------------------------------------------------------
    //                  RECEPCIÓN DEL ARRAY DE BYTES
    //---------------------------------------------------------------------------
    
    //Lo primer es conectarnos con el servidor y hacer la petición de la imagen
    
    char * linea = "image";
    
    //Declaración de variables	
    int sockfd, numbytes;  
    Byte buf[MAXIMAGESIZE];
    struct addrinfo hints, *servinfo, *p;
    int rv;
    char s[INET6_ADDRSTRLEN];
    int bytes_sent;
    char mensaje[50];
    
    printf("Trying to conect to: %s at port %s \n",ip_cadena, port_cadena);
    
    //Formamos el struct hints
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    
    // This function helps set up the structs you need later on.
    if ((rv = getaddrinfo(ip_cadena, port_cadena, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return nil;
    }
    
    // loop through all the results and connect to the first we can
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                             p->ai_protocol)) == -1) {
            perror("client: socket");
            continue;
        }
        
        if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
            close(sockfd);
            perror("client: connect");
            continue;
        }
        
        break;
    }
    
    if (p == NULL) {
        fprintf(stderr, "client: failed to connect\n");
        return NULL;
    }
    
    inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
              s, sizeof s);
    
    
    
    printf("client: connecting to %s\n", s);    
    
    if (bytes_sent = send(sockfd, linea, sizeof(mensaje), 0) == -1) 
        perror("send"); 				
    
    
    
    // ESPERAMOS RECIBIR LA RESPUESTA
    
    //freeaddrinfo(servinfo); // all done with this structure
    
    //    sockfd is the socket descriptor to read from, buf is the buffer to read the information into, len is 
    //    the maximum length of the buffer, and flags can again be set to 0. (See the recv() man page for flag 
    //                                                                        information.) 
    //    recv() returns the number of bytes actually read into the buffer, or -1 on error (with errno set, 
    //                                                                                      accordingly.) 
    //    Wait! recv() can return 0. This can mean only one thing: the remote side has closed the connection 
    //    on you! A return value of  is 's way of letting you know this has occurred. 
    
    int bytes_recibidos = 0;
    void *aux;
    aux = buf;
    
    //Recibimos los bytes en el buffer
    while (bytes_recibidos < 230400) {
        if ((numbytes = recv(sockfd, aux, MAXIMAGESIZE, 0)) == -1) {
            perror("recv");
            exit(1);
        }else{
            bytes_recibidos += numbytes;
            aux = &buf[bytes_recibidos];
        }
        
    }
    
    printf("client: received '%i'\n",bytes_recibidos);
    
    
    int pixelsWide = 320;
    int pixelsHigh = 240;
    char* buffer = malloc(pixelsHigh*pixelsWide*3);
    
    //Una vez recibidos los bytes los copiamos un char* que lo que devolveremos
    for (int i=0; i<pixelsHigh*pixelsWide*3; i++) {
        buffer[i] = buf[i];
    }
    
    close(sockfd);
    return buffer;
}

#pragma mark -
#pragma mark Acciones Interfaz


/*
 Metodo de saludo al robot
 
 */
- (IBAction)helloAction:(id)sender{
    
    NSLog(@"Se ha presionado el botón de hello");
    char * linea = "hello";
    //    NSString *server_ip = [[NSUserDefaults standardUserDefaults] stringForKey:@"server_ip"];
    //    NSString *server_port = [[NSUserDefaults standardUserDefaults] stringForKey:@"server_port"];    
    NSString *server_ip = direccion_ip_host;
    NSString *server_port = puerto_host;
    
    //    NSLog(server_ip);
    //    NSLog(server_port);
    
    //Forma de convertir NSString a char *
    const char *ip_cadena = [server_ip UTF8String];
    const char *port_cadena = [server_port UTF8String];
    
    sendMessage(linea,ip_cadena, port_cadena);
    
}    

/*
 Metodo que hace que el robot ande en linea recta
 */
- (IBAction)walkAction:(id)sender{
    NSLog(@"Se ha presionado el botón de walk");
    char * linea = "walk";
    //    NSString *server_ip = [[NSUserDefaults standardUserDefaults] stringForKey:@"server_ip"];
    //    NSString *server_port = [[NSUserDefaults standardUserDefaults] stringForKey:@"server_port"];    
    
    NSString *server_ip = direccion_ip_host;
    NSString *server_port = puerto_host;
    
    //    NSLog(server_ip);
    //    NSLog(server_port);
    
    //Forma de convertir NSString a char *
    const char *ip_cadena = [server_ip UTF8String];
    const char *port_cadena = [server_port UTF8String];
    sendMessage(linea,ip_cadena, port_cadena);
}


/*
 Metodo para hacer que el robot gire hacia la derecha
 
 */


- (IBAction)turnRightAction:(id)sender{
    NSLog(@"Se ha presionado el botón de turnright");
    char * linea = "turnright";
    //    NSString *server_ip = [[NSUserDefaults standardUserDefaults] stringForKey:@"server_ip"];
    //    NSString *server_port = [[NSUserDefaults standardUserDefaults] stringForKey:@"server_port"];    
    NSString *server_ip = direccion_ip_host;
    NSString *server_port = puerto_host;
    
    //    NSLog(server_ip);
    //    NSLog(server_port);
    
    //Forma de convertir NSString a char *
    const char *ip_cadena = [server_ip UTF8String];
    const char *port_cadena = [server_port UTF8String];
    
    sendMessage(linea,ip_cadena, port_cadena);
    
}

/*
 Metodo para hacer que el robot gire hacia la izquierda
 
 */
- (IBAction)turnLeftAction:(id)sender{
    NSLog(@"Se ha presionado el botón de turnleft");
    char * linea = "turnleft";
    //    NSString *server_ip = [[NSUserDefaults standardUserDefaults] stringForKey:@"server_ip"];
    //    NSString *server_port = [[NSUserDefaults standardUserDefaults] stringForKey:@"server_port"];    
    NSString *server_ip = direccion_ip_host;
    NSString *server_port = puerto_host;
    
    //    NSLog(server_ip);
    //    NSLog(server_port);
    
    //Forma de convertir NSString a char *
    const char *ip_cadena = [server_ip UTF8String];
    const char *port_cadena = [server_port UTF8String];
    
    sendMessage(linea,ip_cadena, port_cadena);
}



/*
 Este método nos permite recibir una imagen de la cámara del robot.
 
 IMPORTANTE: Ha surgido el siguiente problema:
 El sistema de coordenadas del "iphone" se situa en la esquina superior izquierda, no así
 el sistema de "Quartz", la librería gráfica utilizada para pintar la información recibida.
 
 Se ha intentado hacer rotaciones a fin de conseguir poner la imagen tal y como se desea, no obstante
 es necesario una rotación sobre un eje vertical (algo así como dar la vuelta al papel) que hasta ahora no se ha             
 conseguido
 
 */


- (IBAction)recibirImagenAction:(id)sender{
    NSString *server_ip = direccion_ip_host;
    NSString *server_port = puerto_host;
    
    //Forma de convertir NSString a char *
    const char *ip_cadena = [server_ip UTF8String];
    const char *port_cadena = [server_port UTF8String];
    
    char *buffer;    
    buffer = askForImage(ip_cadena, port_cadena);
    
    //                  CODIGO PARA GENERAR UNA IMAGEN ALEATORIO
    //
    //                    int pixelsWide = 320;
    //                    int pixelsHigh = 240;
    //
    //                    char* buffer = malloc(pixelsHigh*pixelsWide*3);
    //                    
    //                    if (buffer == NULL)
    //                    {
    //                        fprintf (stderr, "Memory not allocated!");
    //                    }
    //                    
    //                    int size;
    //                    for (int i=0; i<pixelsHigh*pixelsWide*3; i++) {
    //                        //buffer[i] = rand()%256;
    //                        buffer[i] = 0;
    //                        size = i;
    //                    }
    //                    printf("buffer con tamaño %i",size);

    
    //Quitamos la vista anterior de la pila de vistas
    [self.subview removeFromSuperview];
    
    CGRect rect = CGRectMake(0,0,480,320);
    self.subview = [[PruebaView alloc] initWithFrame:rect buf:buffer];
    //    self.subview.alpha = 0.8;
    [self.view insertSubview:self.subview atIndex:1];        
    
    //Memory management
    [self.subview autorelease];
    
}

/*
 
 Método para hacer que el robor acabe su movimiento
 La idea es hacer que cuando se levante el dedo de cualquiera de los
 botones de movimiento (andar, girar,...) se ejecute este metodo borrando
 los pasos restantes en la pila y haciendo que el robot detenga su  movimiento.
 
 */

- (IBAction)clearFootStepsAction:(id)sender{
    NSLog(@"Se ha presionado el botón de clearFootSteps");
    char * linea = "stop";
    NSString *server_ip = direccion_ip_host;
    NSString *server_port = puerto_host;
    
    //Forma de convertir NSString a char *
    const char *ip_cadena = [server_ip UTF8String];
    const char *port_cadena = [server_port UTF8String];
    
    sendMessage(linea,ip_cadena, port_cadena);
}


/*
 the touchesEnded method which will be called when touches are ended.
 */

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 
    
    //Get all the touches.
    NSSet *allTouches = [event allTouches];
    
    //Number of touches on the screen
    switch ([allTouches count])
    {
        case 1:
        {
            //Get the first touch.
            UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
            
            switch([touch tapCount])
            {
                case 1://Single tap
                    NSLog(@"Toque simple");
                    [self walkAction:self];
                    break;
                case 2://Double tap.
                    NSLog(@"Doble toque");
                    [self clearFootStepsAction:self];
                    break;
                case 3://Double tap.
                    NSLog(@"Triple toque");
                    break;
                    
            }
        } 
            break;
    }
    
}


//-(void) cargarJPEG(char* buffer)
-(void) cargarJPEG
{
     // Esta funcion debera de actualizarse posteriormente una vez la parte servidora funcione
    //      De momento se cargara en la pantalla una foto en png (Imagen 1.png)

//    //Creamos una instancia de NSData con los datos recibidos
//    NSData *datos = [[NSData alloc] initWithBytes:buffer length:longitud]
//    //Creamos una imagen a partir de estos datos
//    UIImage nuevaImagen = [[UIImage imageWithData:datos];
    
    UIImage nuevaImagen = [[UIImage imageNamed:@"Imagen 1.png"];

//    Pasos a seguir:
//        ■ Create a special CGGraphicsContext with a size
//        ■ Draw 
//        ■ Capture the context as a bitmap 
//        ■ Clean up

    
    
//    //Quitamos la vista anterior de la pila de vistas
//    [self.subview removeFromSuperview];
//    
//    CGRect rect = CGRectMake(0,0,480,320);
//    self.subview = [[PruebaView alloc] initWithFrame:rect buf:buffer];
//    //    self.subview.alpha = 0.8;
//    [self.view insertSubview:self.subview atIndex:1];        
//    
//    //Memory management
//    [self.subview autorelease];
    
}
#pragma mark -
#pragma mark Video


- (void)videoImageAction:(id)sender {
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(prueba:) object:self];
    [aQueue addOperation:operation]; 
    [operation release];
}

-(void)prueba:(id)sender
{
    if (videoEstate == (int) VIDEO_OFF){        
        printf("VIDEO_OFF\n");
        
    }
    else{
        printf("VIDEO_ON\n");
        [self recibirImagenAction:self];        
        [self videoImageAction:self];
    }
    
}

- (IBAction)videoAction:(id)sender{

    
    if (videoEstate == (int) VIDEO_OFF){
        //        [video setEnabled:YES];
        //        [video setTitle: @"Finalizar Video" forState: UIControlStateApplication];     
        videoEstate = (int) VIDEO_ON;
        [self videoImageAction:self];
//        NSThread* myThread = [[NSThread alloc] initWithTarget:self
//                                                     selector:@selector(videoMainRoutine) object:nil];
//        [myThread start];  // Actually create the thread
    }
    else{
        //        [video setHighlighted:NO];
        //        [video setTitle: @"Empezar Video" forState: UIControlStateApplication];     
        videoEstate = (int) VIDEO_OFF;
    }
}




- (void)videoMainRoutine
{
    while(videoEstate == (int) VIDEO_ON){
        [self videoImageAction:self];
    }
}

#pragma mark -

- (void)didReceiveMemoryWarning {
	// Releases the view if it doesn't have a superview.
    NSLog(@"RECIBIDO MEMORY WARNING!!!");
    [super didReceiveMemoryWarning];
	
	// Release any cached data, images, etc that aren't in use.
}


@end
